package com.sky.tank.panel;

import com.sky.tank.basic.BaseWar;
import com.sky.tank.basic.Piece;
import com.sky.tank.basic.PlayVoice;
import com.sky.tank.basic.Tank;
import com.sky.tank.data.ImageIconData;
import com.sky.tank.enums.DirectionTank;
import lombok.Data;
import lombok.EqualsAndHashCode;

import javax.swing.*;
import javax.swing.Timer;
import java.awt.*;
import java.awt.event.*;

import java.util.*;
import java.util.List;


/**
 * @author sky
 * @version 1.0
 * @date 2022/5/17 15:05:33
 */

@Data
@EqualsAndHashCode(callSuper = true)
public class War extends BaseWar implements KeyListener, ActionListener {
    public static BaseWar instance = new War().getInstance();
    public final static int DEFAULT_GAME_FRAME = 50;
    private OtherProperties other;
    private Set<DirectionTank> cantMoved;
    private JPanel battlePanel;
    private JPanel shadow;
    private java.util.List<Tank.Bullet> bullets;
    private Timer tMove;
    private Timer addBulletTimer;
    private java.util.List<Tank> enemy;
    private Random ra = new Random();
    private Timer enemyTimer;

    private boolean gameStop = false;
    private boolean gameOver = false;


    /**
     * 帧率
     */
    public int gameFrame = 50;

    private Timer timer;

    public War() {
        super();
    }

    /**
     * 初始化
     */
    public void init() {
        this.setLayout(null);
        this.gameFrame = DEFAULT_GAME_FRAME;
        timer = new Timer(1000 / gameFrame, this);

        cantMoved = new HashSet<>();
        bullets = new Vector<>();
        enemy = new ArrayList<>();

        Tank tank = new Tank(3)
                .setX(0)
                .setY(0)
                .setDirection(DirectionTank.DOWN);
        tank.setBullet(new Tank.Bullet(17, 17, 12, ImageIconData.BULLET_OWN).setTank(tank));
        tank.setBullets(new ArrayList<>());
        //每隔1.5秒跑十八步
        tank.setBodyMove(new Timer(100,(e)->{
            autoMove(tank);
        }));
        //每隔一秒发射一颗子弹
        tank.setBulletMove(new Timer(1000,(e)->{
            addBullet(tank,this.bullets);
        }));
        enemy.add(tank);


        battlePanel = new JPanel() {
            @Override
            protected void paintComponent(Graphics g) {
                for (Piece piece : battle) {
                    piece.getPic().paintIcon(battlePanel, g, piece.x, piece.y);
                }
            }
        };
        battlePanel.setLocation(left, top);
        battlePanel.setSize(latticeX * lattice, latticeY * lattice);
        add(battlePanel);
        timer.start();
        tMove = new Timer(1000 / gameFrame, (e) -> {
            tankMove();
            tMove.start();
        });

        addBulletTimer = new Timer(1000/gameFrame,(e)->{
            addBullet(this.tank,this.bullets);
            addBulletTimer.start();
        });

        //音乐
        //new PlayVoice("start.wav").start();

    }

    public synchronized Set<DirectionTank> enemyCantMove(Tank tank){
        Set<DirectionTank> cantMoved = new HashSet<>();
        for (Piece p : battle) {
            if (tank.y + tank.height > p.y && tank.y < p.y + p.height) {
                if (tank.x + tank.width >= p.x && tank.x + tank.width < p.x + tank.speed) {
                    tank.x = p.x - tank.width;
                    cantMoved.add(DirectionTank.RIGHT);
                }

                if (tank.x >= p.x + p.width - tank.speed && tank.x <= p.x + p.width) {
                    tank.x = p.x + p.width;
                    cantMoved.add(DirectionTank.LEFT);
                }
            }

            if (tank.x + tank.width > p.x && tank.x < p.x + p.width) {
                if (tank.y > p.y + p.height - tank.speed && tank.y <= p.y + p.height) {
                    tank.y = p.y + p.height;
                    cantMoved.add(DirectionTank.UP);
                }

                if (tank.y + tank.height >= p.y && tank.y + tank.height < p.y + tank.speed) {
                    tank.y = p.y - tank.height;
                    cantMoved.add(DirectionTank.DOWN);
                }
            }
        }
        return cantMoved;
    }

    public synchronized void tankMoving(Tank tank){
        switch (tank.direction) {
            case LEFT:
                tank.x -= tank.speed;
                break;
            case RIGHT:
                tank.x += tank.speed;
                break;
            case UP:
                tank.y -= tank.speed;
                break;
            case DOWN:
                tank.y += tank.speed;
                break;
            default:
        }
    }

    @Override
    public synchronized void tankMove() {
        cantMoved = enemyCantMove(tank);
        if (!cantMoved.contains(tank.direction)) {
            tankMoving(tank);
        }
    }


    public War getInstance() {
        setTop(0);
        setLeft(0);
        other = new OtherProperties();

        Tank tank = new Tank(6)
                .setX(240)
                .setY(660);

        tank.setBullet(new Tank.Bullet(17, 17, 12, ImageIconData.BULLET_OWN).setTank(tank));

        this.setTank(tank);

        this.loadWall();

        setFocusable(true);
        addKeyListener(this);
        setBounds(left, top, latticeX * lattice, latticeY * lattice);

        this.init();

        return this;
    }

    @Override
    protected void paintComponent(Graphics g) {
        if(gameOver){
            g.setColor(Color.RED);
            g.setFont(new Font("微软雅黑",Font.BOLD,40));
            g.drawString("GAME OVER",100,400);
            return;
        }
        if(gameStop){
            g.setColor(new Color(136, 127, 127, 90));
            g.fillRect(0,0,other.warWidth,other.warHeight);
            g.setColor(Color.RED);
            g.setFont(new Font("微软雅黑",Font.BOLD,40));
            g.drawString("游戏暂停",100,400);

        }else {
            g.setColor(Color.BLACK);
            g.fillRect(left, top, latticeX * lattice, latticeY * lattice);
            ImageIconData.getOwnTank(tank.direction)
                    .paintIcon(this, g, tank.x, tank.y);
            for (Tank tank1 : enemy) {
                ImageIconData.getGreyTank(tank1.direction)
                        .paintIcon(this, g, tank1.x, tank1.y);
                tank1.bodyMove.start();
                tank1.bulletMove.start();
            }

            Iterator<Tank.Bullet> itBullet = bullets.iterator();
            while (itBullet.hasNext()) {
                Tank.Bullet bullet = itBullet.next();
                bullet.img.paintIcon(this, g, bullet.x, bullet.y);
                bullet.move();
                if (bullet.x <= left || bullet.x >= other.warWidth || bullet.y <= top || bullet.y >= other.warHeight) {
                    itBullet.remove();
                    continue;
                }
                Iterator<Piece> pieceIterator = battle.iterator();
                while (pieceIterator.hasNext()) {
                    Piece w = pieceIterator.next();
                    if (!(bullet.x + bullet.width <= w.x || bullet.x >= w.x + w.width ||
                            bullet.y + bullet.height <= w.y || bullet.y >= w.y + w.height)) {
                        if (w.canDestroy) {
                            pieceIterator.remove();
                        }
                        try {
                            itBullet.remove();
                        } catch (Exception e) {
                        }
                    }
                }
            }
        }
    }

    @Override
    public void keyTyped(KeyEvent e) {

    }

    public void autoMove(Tank t){
        Set<DirectionTank> cantMove = enemyCantMove(t);
        //不能直行
        if(cantMove.contains(t.direction)){
            List<DirectionTank> tmp = new ArrayList<>();
            for (DirectionTank move : other.tankMoves) {
                if (!cantMove.contains(move)) {
                    tmp.add(move);
                }
            }
            t.direction = tmp.get(ra.nextInt(tmp.size()));
        }else{
            tankMoving(t);
        }
    }


    @Override
    public void keyPressed(KeyEvent e) {
        int keyCode = e.getKeyCode();
        if(!gameOver) {
            if (keyCode == KeyEvent.VK_LEFT && tank.direction != DirectionTank.LEFT) {
                tank.direction = DirectionTank.LEFT;
            } else if (keyCode == KeyEvent.VK_RIGHT && tank.direction != DirectionTank.RIGHT) {
                tank.direction = DirectionTank.RIGHT;
            } else if (keyCode == KeyEvent.VK_UP && tank.direction != DirectionTank.UP) {
                tank.direction = DirectionTank.UP;
            } else if (keyCode == KeyEvent.VK_DOWN && tank.direction != DirectionTank.DOWN) {
                tank.direction = DirectionTank.DOWN;
            } else if (keyCode == KeyEvent.VK_P) {
                tMove.stop();
                gameOver = true;
            } else {
                if (other.moveKeyCode.contains(keyCode)) {
                    tMove.start();
                }
            }

            if (keyCode == KeyEvent.VK_CONTROL) {
                addBulletTimer.start();
            }
        }else{
            if(keyCode == KeyEvent.VK_P){
                gameOver = false;
            }
        }

    }

    public void addBullet(Tank tank, java.util.List<Tank.Bullet> b){
        other.lastBulletTime = System.currentTimeMillis();
        if (other.lastBulletTime - other.beginBulletTime >= tank.fillingTime) {
            other.beginBulletTime = other.lastBulletTime;
            b.add(tank.bullet.initLocation());
        }
    }

    @Override
    public void keyReleased(KeyEvent e) {
        if(other.moveKeyCode.contains(e.getKeyCode())){
            tMove.stop();
        }

        if(e.getKeyCode() == KeyEvent.VK_CONTROL){
            addBulletTimer.stop();
        }
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        repaint();
        timer.start();
    }

    @Override
    public void loadWall() {
        battle = new ArrayList<>();

        //1
        battle.add(new Piece(0,390,30,30).setPic(ImageIconData.WALL));
        battle.add(new Piece(30,390,30,30).setPic(ImageIconData.WALL));
        battle.add(new Piece(0,420,60,30).setPic(ImageIconData.STONE_H).setCanDestroy(false));

        //2
        battle.add(new Piece(60, 60, 60, 60).setPic(ImageIconData.WALLS));
        battle.add(new Piece(60, 120, 60, 60).setPic(ImageIconData.WALLS));
        battle.add(new Piece(60, 180, 60, 60).setPic(ImageIconData.WALLS));
        battle.add(new Piece(60, 240, 60, 60).setPic(ImageIconData.WALLS));
        battle.add(new Piece(60, 300, 30, 30).setPic(ImageIconData.WALL));
        battle.add(new Piece(90, 300, 30, 30).setPic(ImageIconData.WALL));
        battle.add(new Piece(60, 510, 60, 60).setPic(ImageIconData.WALLS));
        battle.add(new Piece(60, 570, 60, 60).setPic(ImageIconData.WALLS));
        battle.add(new Piece(60, 630, 60, 60).setPic(ImageIconData.WALLS));
        battle.add(new Piece(60, 690, 30, 30).setPic(ImageIconData.WALL));
        battle.add(new Piece(90, 690, 30, 30).setPic(ImageIconData.WALL));
        //3
        battle.add(new Piece(120, 390, 60, 60).setPic(ImageIconData.WALLS));

        //4
        battle.add(new Piece(180, 60, 60, 60).setPic(ImageIconData.WALLS));
        battle.add(new Piece(180, 120, 60, 60).setPic(ImageIconData.WALLS));
        battle.add(new Piece(180, 180, 60, 60).setPic(ImageIconData.WALLS));
        battle.add(new Piece(180, 240, 60, 60).setPic(ImageIconData.WALLS));
        battle.add(new Piece(180, 300, 30, 30).setPic(ImageIconData.WALL));
        battle.add(new Piece(210, 300, 30, 30).setPic(ImageIconData.WALL));
        battle.add(new Piece(180, 390, 60, 60).setPic(ImageIconData.WALLS));
        battle.add(new Piece(180, 510, 60, 60).setPic(ImageIconData.WALLS));
        battle.add(new Piece(180, 570, 60, 60).setPic(ImageIconData.WALLS));
        battle.add(new Piece(180, 630, 60, 60).setPic(ImageIconData.WALLS));
        battle.add(new Piece(180, 690, 30, 30).setPic(ImageIconData.WALL));
        battle.add(new Piece(210, 690, 30, 30).setPic(ImageIconData.WALL));

        //6
        battle.add(new Piece(300, 60, 60, 60).setPic(ImageIconData.WALLS));
        battle.add(new Piece(300, 120, 60, 60).setPic(ImageIconData.WALLS));
        battle.add(new Piece(300, 180, 60, 60).setPic(ImageIconData.WALLS));
        battle.add(new Piece(300, 240, 30, 30).setPic(ImageIconData.WALL));
        battle.add(new Piece(330, 240, 30, 30).setPic(ImageIconData.WALL));

        battle.add(new Piece(300, 330, 60, 60).setPic(ImageIconData.WALLS));

        battle.add(new Piece(300, 450, 60, 60).setPic(ImageIconData.WALLS));
        battle.add(new Piece(300, 510, 60, 60).setPic(ImageIconData.WALLS));
        battle.add(new Piece(300, 570, 60, 60).setPic(ImageIconData.WALLS));

        //7
        battle.add(new Piece(360, 180, 60, 60).setPic(ImageIconData.STONE_ALL).setCanDestroy(false));
        battle.add(new Piece(360, 480, 60, 60).setPic(ImageIconData.WALLS));

        //8
        battle.add(new Piece(420, 60, 60, 60).setPic(ImageIconData.WALLS));
        battle.add(new Piece(420, 120, 60, 60).setPic(ImageIconData.WALLS));
        battle.add(new Piece(420, 180, 60, 60).setPic(ImageIconData.WALLS));
        battle.add(new Piece(420, 240, 30, 30).setPic(ImageIconData.WALL));
        battle.add(new Piece(450, 240, 30, 30).setPic(ImageIconData.WALL));

        battle.add(new Piece(420, 330, 60, 60).setPic(ImageIconData.WALLS));

        battle.add(new Piece(420, 450, 60, 60).setPic(ImageIconData.WALLS));
        battle.add(new Piece(420, 510, 60, 60).setPic(ImageIconData.WALLS));
        battle.add(new Piece(420, 570, 60, 60).setPic(ImageIconData.WALLS));

        //10
        battle.add(new Piece(540, 60, 60, 60).setPic(ImageIconData.WALLS));
        battle.add(new Piece(540, 120, 60, 60).setPic(ImageIconData.WALLS));
        battle.add(new Piece(540, 180, 60, 60).setPic(ImageIconData.WALLS));
        battle.add(new Piece(540, 240, 60, 60).setPic(ImageIconData.WALLS));
        battle.add(new Piece(540, 300, 30, 30).setPic(ImageIconData.WALL));
        battle.add(new Piece(570, 300, 30, 30).setPic(ImageIconData.WALL));
        battle.add(new Piece(540, 390, 60, 60).setPic(ImageIconData.WALLS));
        battle.add(new Piece(540, 510, 60, 60).setPic(ImageIconData.WALLS));
        battle.add(new Piece(540, 570, 60, 60).setPic(ImageIconData.WALLS));
        battle.add(new Piece(540, 630, 60, 60).setPic(ImageIconData.WALLS));
        battle.add(new Piece(540, 690, 30, 30).setPic(ImageIconData.WALL));
        battle.add(new Piece(570, 690, 30, 30).setPic(ImageIconData.WALL));

        //11
        battle.add(new Piece(600, 390, 60, 60).setPic(ImageIconData.WALLS));

        //12
        battle.add(new Piece(660, 60, 60, 60).setPic(ImageIconData.WALLS));
        battle.add(new Piece(660, 120, 60, 60).setPic(ImageIconData.WALLS));
        battle.add(new Piece(660, 180, 60, 60).setPic(ImageIconData.WALLS));
        battle.add(new Piece(660, 240, 60, 60).setPic(ImageIconData.WALLS));
        battle.add(new Piece(660, 300, 30, 30).setPic(ImageIconData.WALL));
        battle.add(new Piece(690, 300, 30, 30).setPic(ImageIconData.WALL));
        battle.add(new Piece(660, 510, 60, 60).setPic(ImageIconData.WALLS));
        battle.add(new Piece(660, 570, 60, 60).setPic(ImageIconData.WALLS));
        battle.add(new Piece(660, 630, 60, 60).setPic(ImageIconData.WALLS));
        battle.add(new Piece(660, 690, 30, 30).setPic(ImageIconData.WALL));
        battle.add(new Piece(690, 690, 30, 30).setPic(ImageIconData.WALL));

        //13
        battle.add(new Piece(720,390,30,30).setPic(ImageIconData.WALL));
        battle.add(new Piece(750,390,30,30).setPic(ImageIconData.WALL));
        battle.add(new Piece(720,420,60,30).setPic(ImageIconData.STONE_H).setCanDestroy(false));


        //boss
        battle.add(new Piece(330,690,30,30).setPic(ImageIconData.WALL));
        battle.add(new Piece(330,720,30,30).setPic(ImageIconData.WALL));
        battle.add(new Piece(330,750,30,30).setPic(ImageIconData.WALL));
        battle.add(new Piece(360,690,30,30).setPic(ImageIconData.WALL));
        battle.add(new Piece(390,690,30,30).setPic(ImageIconData.WALL));
        battle.add(new Piece(420,690,30,30).setPic(ImageIconData.WALL));
        battle.add(new Piece(420,720,30,30).setPic(ImageIconData.WALL));
        battle.add(new Piece(420,750,30,30).setPic(ImageIconData.WALL));
        battle.add(new Piece(360,720,60,60).setPic(ImageIconData.OWN_BOSS));






        battle.add(Piece.initWall(0, -tank.speed, other.warWidth, tank.speed));
        battle.add(Piece.initWall(0, other.warHeight, other.warWidth, tank.speed));


        battle.add(Piece.initWall(-tank.speed, 0, tank.speed, other.warHeight));
        battle.add(Piece.initWall(other.warWidth, 0, tank.speed, other.warHeight));

    }

    private class OtherProperties {
        protected ArrayList<Integer> moveKeyCode;
        protected int warWidth;
        protected int warHeight;
        protected long lastBulletTime;
        protected long beginBulletTime;
        protected java.util.List<DirectionTank> tankMoves;

        protected OtherProperties() {
            moveKeyCode = new ArrayList<>(4);
            moveKeyCode.add(KeyEvent.VK_LEFT);
            moveKeyCode.add(KeyEvent.VK_RIGHT);
            moveKeyCode.add(KeyEvent.VK_UP);
            moveKeyCode.add(KeyEvent.VK_DOWN);

            warWidth = latticeX * lattice;
            warHeight = latticeY * lattice;
            beginBulletTime = 0;
            lastBulletTime = System.currentTimeMillis();

            tankMoves = Arrays.asList(DirectionTank.UP,DirectionTank.DOWN,DirectionTank.LEFT,DirectionTank.RIGHT);
        }
    }
}
